package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.article.dto.ArticleStreamMessage;
import com.heima.article.entity.ApArticle;
import com.heima.article.service.IApArticleService;
import com.heima.article.service.IHotArticleService;
import com.heima.article.vo.HotArticleVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class IHotArticleServiceImpl implements IHotArticleService {

    @Autowired
    private IApArticleService iApArticleService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public void compute() {
        //查询5天的文章
        Date date = new Date();
        Date now = new Date(date.getYear(), date.getMonth(), date.getDay());
        Date before = new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000);
        LambdaQueryWrapper<ApArticle> query = new LambdaQueryWrapper<>();
        query.gt(ApArticle::getPublishTime, before);
        query.lt(ApArticle::getPublishTime, now);
        List<ApArticle> apArticleList = iApArticleService.list(query);
        //计算分值
        List<HotArticleVo> articleVoList = new ArrayList<>();
        for (ApArticle apArticle : apArticleList) {
            HotArticleVo vo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle, vo);

            //计算分数
            int score = getScore(apArticle);
            vo.setScore(score);
            articleVoList.add(vo);
        }
        //缓存到redis
        articleVoList.sort(new Comparator<HotArticleVo>() {
            @Override
            public int compare(HotArticleVo o1, HotArticleVo o2) {
                return o2.getScore() - o1.getScore();
            }
        });
        int size = 30;
        if (articleVoList.size() <= 30) {
            size = articleVoList.size();
        }
        List<HotArticleVo> hotArticleVoList = articleVoList.subList(0, size);
        String recommendHotArticle = "hot_article_recommendHotArticle";
        redisTemplate.opsForValue().set(recommendHotArticle, JSON.toJSONString(hotArticleVoList));
        //给每个频道缓存
        Map<Integer, List<HotArticleVo>> channelMap = new HashMap<>();
        for (HotArticleVo vo : articleVoList) {
            Integer channelId = vo.getChannelId();
            if (channelMap.containsKey(channelId)) {
                channelMap.get(channelId).add(vo);
            } else {
                List<HotArticleVo> vos = new ArrayList<>();
                vos.add(vo);
                channelMap.put(channelId, vos);
            }
        }
        for (Map.Entry<Integer, List<HotArticleVo>> integerListEntry : channelMap.entrySet()) {
            List<HotArticleVo> value = integerListEntry.getValue();
            value.sort(new Comparator<HotArticleVo>() {
                @Override
                public int compare(HotArticleVo o1, HotArticleVo o2) {
                    return o2.getScore() - o1.getScore();
                }
            });
            if (value.size() <= 30) {
                size = value.size();
            }
            value.subList(0, size);
            String HotChannelArticle = "hot_article_HotArticle" + integerListEntry.getKey();
            redisTemplate.opsForValue().set(HotChannelArticle, JSON.toJSONString(value));
        }
    }

    @Override
    public void update(ArticleStreamMessage articleStreamMessage) {
        //根据文章Id查询文章
        ApArticle apArticle = iApArticleService.getById(articleStreamMessage.getArticleId());
        HotArticleVo vo = new HotArticleVo();
        BeanUtils.copyProperties(apArticle, vo);
        //获取当前文章的分值
        int score = getScore(apArticle);
        // 重新计算分值，当日的文章权重*3
        int add = getScore(articleStreamMessage);

        vo.setScore(score + add);
        //更新redis中的数据
        //查询当前文章是否在列表中，如果在，重新排序，如果不在，取最后一位，对比分值，如果比它大，就替换，重新排序
        String hot_article_recommendHotArticle = redisTemplate.opsForValue().get("hot_article_recommendHotArticle");
        List<HotArticleVo> hotArticleVos = JSON.parseArray(hot_article_recommendHotArticle, HotArticleVo.class);
        //当前ID是否在查询列表中
        boolean exist = false;
        for (HotArticleVo hotArticleVo : hotArticleVos) {
            if (hotArticleVo.getId().equals(articleStreamMessage.getArticleId())) {
                exist = true;
                hotArticleVo.setScore(vo.getScore());
                break;
            }
        }
        hotArticleVos.sort(new Comparator<HotArticleVo>() {
            @Override
            public int compare(HotArticleVo o1, HotArticleVo o2) {
                return o2.getScore() - o1.getScore();
            }
        });
        //更新redis里的文章
        int size = 30;
        if (hotArticleVos.size() <= 30) {
            size = hotArticleVos.size();
        }
        List<HotArticleVo> subList = hotArticleVos.subList(0, size);
        redisTemplate.opsForValue().set(hot_article_recommendHotArticle, JSON.toJSONString(subList));
        //每个频道也要更新  //todo
        LambdaUpdateWrapper<ApArticle> update = new LambdaUpdateWrapper<>();
        update.eq(ApArticle::getId, articleStreamMessage.getArticleId());
        update.setSql("views=views" + articleStreamMessage.getView());
        update.setSql("likes=likes" + articleStreamMessage.getLike());
        update.setSql("comment=comment" + articleStreamMessage.getComment());
        update.setSql("collection=collection" + articleStreamMessage.getCollect());
        iApArticleService.update(update);
    }

    //计算增量分数
    private int getScore(ArticleStreamMessage articleStreamMessage) {
        // 阅读：1，点赞：3，评论：5，收藏：8
        int score = 0;
        score += articleStreamMessage.getView() * 3;
        score += articleStreamMessage.getLike() * 3 * 3;
        score += articleStreamMessage.getComment() * 5 * 3;
        score += articleStreamMessage.getCollect() * 8 * 3;
        return score;
    }

    private int getScore(ApArticle apArticle) {
        int count = 0;
        if (apArticle.getViews() != null) {
            count = count + apArticle.getViews() * 1;
        }

        if (apArticle.getLikes() != null) {
            count = count + apArticle.getLikes() * 3;
        }

        if (apArticle.getComment() != null) {
            count = count + apArticle.getComment() * 5;
        }

        if (apArticle.getCollection() != null) {
            count = count + apArticle.getCollection() * 8;
        }
        return count;
    }
}
